package org.icec.common.utils;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Properties;

import javax.activation.DataHandler;
import javax.activation.FileDataSource;
import javax.mail.Address;
import javax.mail.Authenticator;
import javax.mail.BodyPart;
import javax.mail.Message;
import javax.mail.Multipart;
import javax.mail.PasswordAuthentication;
import javax.mail.Session;
import javax.mail.Transport;
import javax.mail.internet.InternetAddress;
import javax.mail.internet.MimeBodyPart;
import javax.mail.internet.MimeMessage;
import javax.mail.internet.MimeMultipart;
import javax.mail.internet.MimeUtility;

import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.alibaba.fastjson.JSONArray;

/**
 * @author system
 * @date 2018/01/01
 * @desc 邮件工具类
 */
public class EmailUtil {

    private static final Logger LOG = LoggerFactory.getLogger(EmailUtil.class);

    private static String USER_NAME = "";
    private static String PASSWORD = "";

    public static void init(String userName, String password) {
        USER_NAME = userName;
        PASSWORD = password;
    }

    private static final String HOST = "smtp.qq.com";
    private static final String PORT = "465";

    private static final String ENCODING = "UTF-8";

    private static final Properties PROPERTIES = new Properties();

    static {
        PROPERTIES.put("mail.smtp.auth", "true");
        PROPERTIES.put("mail.smtp.host", HOST);
        PROPERTIES.put("mail.smtp.port", PORT);
        PROPERTIES.put("mail.smtp.socketFactory.class", "javax.net.ssl.SSLSocketFactory");
        PROPERTIES.put("mail.smtp.socketFactory.port", PORT);
    }

    public static void sendMail(MailSetting mailSetting) {
        // 校验参数
        boolean checkResult = checkParameter(mailSetting);
        if (!checkResult) {
            return;
        }
        Session mailSession = Session.getInstance(PROPERTIES, getAuthenticator(USER_NAME, PASSWORD));
        try {
            // 根据session创建一个邮件消息
            MimeMessage message = new MimeMessage(mailSession);
            // 配置邮件
            settingMail(USER_NAME, message, mailSetting);
            // 发送
            send(USER_NAME, mailSession, message);
        } catch (Exception ex) {
            LOG.error("send mail error:" + ex.getMessage(), ex);
        }
    }

    private static Authenticator getAuthenticator(String userName, String password) {
        return new Authenticator() {
            @Override
            protected PasswordAuthentication getPasswordAuthentication() {
                return new PasswordAuthentication(userName, password);
            }
        };
    }

    private static void settingMail(String userName, MimeMessage message, MailSetting mailSetting) throws Exception {
        // 设置地址
        setAddress(userName, message, mailSetting);

        // 设置主题
        message.setSubject(mailSetting.getSubject());
        message.addHeader("charset", ENCODING);

        // 设置正文内容和附件
        setContentAndAttachFile(message, mailSetting);
    }

    private static void setAddress(String userName, MimeMessage message, MailSetting mailSetting) throws Exception {
        // 设置发送地址
        Address fromAddress = new InternetAddress(userName);
        message.setFrom(fromAddress);

        // 设置接收地址
        message.setRecipients(Message.RecipientType.TO, getReceiveAddress(mailSetting));

        // 设置抄送地址
        JSONArray ccAddress = mailSetting.getCcAddress();
        if (ccAddress != null && ccAddress.size() > 0) {
            int ccSize = ccAddress.size();
            Address[] ccAddressArray = new Address[ccSize];
            for (int i = 0; i < ccSize; i++) {
                ccAddressArray[i] = new InternetAddress(ccAddress.getString(i));
            }
            message.setRecipients(Message.RecipientType.CC, ccAddressArray);
        }
    }

    private static Address[] getReceiveAddress(MailSetting mailSetting) throws Exception {
        JSONArray jsonArray = mailSetting.getToAddress();
        int size = jsonArray.size();
        Address[] addressArray = new Address[size];
        for (int i = 0; i < size; i++) {
            addressArray[i] = new InternetAddress(jsonArray.getString(i));
        }
        return addressArray;
    }

    private static void setContentAndAttachFile(MimeMessage message, MailSetting mailSetting) throws Exception {
        // 正文内容
        Multipart multipart = new MimeMultipart();
        BodyPart contentPart = new MimeBodyPart();
        contentPart.setText(mailSetting.getContent());
        contentPart.setHeader("Content-Type", "text/html; charset=UTF-8");
        multipart.addBodyPart(contentPart);

        // 附件
        List<String> attachFileNameList = mailSetting.getAttachFileNames();
        if (CollectionUtils.isNotEmpty(attachFileNameList)) {
            for (String attachFile : attachFileNameList) {
                BodyPart bodyPart = new MimeBodyPart();
                FileDataSource fds = new FileDataSource(attachFile);
                bodyPart.setDataHandler(new DataHandler(fds));
                bodyPart.setFileName(MimeUtility.encodeText(fds.getName()));
                multipart.addBodyPart(bodyPart);
            }
        }
        message.setContent(multipart);
    }

    private static void send(String userName, Session mailSession, MimeMessage message) throws Exception {
        Transport transport = mailSession.getTransport("smtp");
        transport.connect(HOST, PORT, userName);
        transport.sendMessage(message, message.getAllRecipients());
        transport.close();
    }

    private static boolean checkParameter(MailSetting mailSetting) {
        if (mailSetting == null) {
            LOG.error("This is a mail without any setting");
            return false;
        }
        if (mailSetting.getToAddress() == null || mailSetting.getToAddress().size() < 1) {
            LOG.error("This is a mail without any toAddress");
            return false;
        }
        if (StringUtils.isBlank(mailSetting.getSubject())) {
            LOG.error("This is a mail without subject");
            return false;
        }
        if (StringUtils.isBlank(mailSetting.getContent())) {
            LOG.error("This is a mail without content");
            return false;
        }
        return true;
    }

    public static MailSetting getMailSetting() {
        return new MailSetting();
    }

    public static class MailSetting {
        private MailSetting() {}

        /**
         * 邮件接收者 一个或者多个
         */
        private JSONArray toAddress;

        /**
         * 抄送 一个或者多个
         */
        private JSONArray ccAddress;

        /**
         * 邮件主题
         */
        private String subject;

        /**
         * 邮件内容
         */
        private String content;

        /**
         * 邮件附件
         */
        private List<String> attachFileNames;

        public void setToAddress(String toAddress) {
            checkToAddress();
            this.toAddress.add(toAddress);
        }

        public void setToAddress(JSONArray toAddressArray) {
            checkToAddress();
            this.toAddress.addAll(toAddressArray);
        }

        public void setToAddress(String[] addressArray) {
            setToAddress(Arrays.asList(addressArray));
        }

        public void setToAddress(List<String> addressList) {
            checkToAddress();
            this.toAddress.addAll(addressList);
        }

        private void checkToAddress() {
            if (this.toAddress == null) {
                this.toAddress = new JSONArray();
            }
        }

        private JSONArray getToAddress() {
            return this.toAddress;
        }

        public void setCcAddress(String toAddress) {
            checkCcAddress();
            this.ccAddress.add(toAddress);
        }

        public void setCcAddress(JSONArray toAddressArray) {
            checkCcAddress();
            this.ccAddress.addAll(toAddressArray);
        }

        public void setCcAddress(String[] toAddressList) {
            setCcAddress(Arrays.asList(toAddressList));
        }

        public void setCcAddress(List<String> toAddressList) {
            checkCcAddress();
            this.ccAddress.addAll(toAddressList);
        }

        private void checkCcAddress() {
            if (this.ccAddress == null) {
                this.ccAddress = new JSONArray();
            }
        }

        private JSONArray getCcAddress() {
            return this.ccAddress;
        }

        private String getSubject() {
            return subject;
        }

        public void setSubject(String subject) {
            this.subject = subject;
        }

        private String getContent() {
            return content;
        }

        public void setContent(String content) {
            this.content = content;
        }

        private List<String> getAttachFileNames() {
            return attachFileNames;
        }

        public void setAttachFileNames(List<String> attachFileNames) {
            this.attachFileNames = attachFileNames;
        }

        public void setAttachFileNames(String[] attachFileNames) {
            setAttachFileNames(Arrays.asList(attachFileNames));
        }

        public void setAttachFileNames(String attachFileName) {
            if (this.attachFileNames == null) {
                this.attachFileNames = new ArrayList<>(16);
            }
            this.attachFileNames.add(attachFileName);
        }
    }
}
